package server

import (
	"cloud-entropy-storage-system/common/pb/pbfiles"
	"cloud-entropy-storage-system/common/pkg/logger"
	"cloud-entropy-storage-system/common/pkg/pathdir"
	"cloud-entropy-storage-system/volume/internal/config"
	"cloud-entropy-storage-system/volume/internal/logic"
	"fmt"
	"github.com/asdine/storm/v3"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"log"
	"net"
	"path"
	"time"
)

type Server struct {
	db      *storm.DB
	manager *logic.Manager
	vol     *logic.Volume
	cfg     config.Config
	conn    *grpc.ClientConn
	log     *zap.Logger
}

func NewServer(cfg config.Config) *Server {
	s := new(Server)
	s.cfg = cfg
	s.log = logger.New(cfg.Log.Dir, cfg.Log.ServerName)
	s.db = s.initDB()                 // 优先初始化db连接
	s.conn = s.initManagerClient()    // 连接manager rpc服务
	s.manager = s.initVolumeManager() // 初始化volume,并向manager发送心跳包
	go s.startRpcServer()             // 初始化store rpc server服务，开始接收文件请求
	return s
}

func (s *Server) initDB() *storm.DB {
	if _, err := pathdir.CheckAndMkDir(s.cfg.DataDir); err != nil {
		log.Fatalln("initDB err:", err)
		return nil
	}
	db, err := storm.Open(path.Join(s.cfg.DataDir, "gofile.s3w"))
	if err != nil {
		log.Fatalln(err)
		return nil
	}
	return db
}

func (s *Server) initManagerClient() *grpc.ClientConn {
	log.Println("准备连接manager rpc接口")
	// 阻塞式连接
	conn, err := grpc.Dial(fmt.Sprintf("%s:%d", s.cfg.ManagerServer.Host, s.cfg.ManagerServer.Port),
		grpc.WithInsecure(),
		grpc.WithBlock(),
		grpc.WithBackoffMaxDelay(time.Second),
		grpc.WithDefaultCallOptions(
			grpc.MaxCallRecvMsgSize(s.cfg.MaxRevSize),
			grpc.MaxCallSendMsgSize(s.cfg.MaxRevSize),
		), // 最大接收200MB
	)
	// conn.GetState(): READY
	if err != nil {
		log.Fatalln("连接失败", err)
	}
	log.Println("连接manager rpc接口成功")
	return conn
}

func (s *Server) initVolumeManager() *logic.Manager {
	vm, err := logic.NewVolumeManager(logic.NewVolumeReq{
		HttpHost:   s.cfg.HttpHost,
		DataCenter: fmt.Sprintf("%s:%d", s.cfg.StorageServer.Host, s.cfg.StorageServer.Port),
		StoreName:  s.cfg.Name, Dir: s.cfg.StorageDir, HeartWait: s.cfg.HeartbeatWait,
		HeartTimeout: s.cfg.HeartTimeout, MaxVolSize: uint64(s.cfg.MaxVolumeSize),
		MaxDiskUsed: uint64(s.cfg.MaxDiskUsed), Conn: s.conn, DB: s.db, Log: s.log})
	if err != nil {
		log.Fatalln("初始化storage失败")
	}
	vm.Start()
	return vm
}

func (s *Server) startRpcServer() {
	lis, err := net.Listen("tcp",
		fmt.Sprintf("%s:%d", s.cfg.StorageServer.Host, s.cfg.StorageServer.Port))
	if err != nil {
		log.Fatalln("failed to listen:", err)
	}
	var options = []grpc.ServerOption{
		grpc.MaxRecvMsgSize(s.cfg.MaxRevSize),
		grpc.MaxSendMsgSize(s.cfg.MaxRevSize),
	}
	grpcServer := grpc.NewServer(options...)

	pbfiles.RegisterUploadRpcServer(grpcServer, s.manager)
	pbfiles.RegisterVolumeFileServer(grpcServer, s.manager)

	if err = grpcServer.Serve(lis); err != nil {
		log.Fatalln("启动失败", err)
	}
}

func (s *Server) Close() {
	if err := s.db.Close(); err != nil {
		s.log.Error(err.Error())
	}
	if err := s.conn.Close(); err != nil {
		s.log.Error(err.Error())
	}
}
